/* Copyright 2009
 *
 * This program and the accompanying materials
 * are made available under the terms of the
 * Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at
 *
 * 		http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
 * OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * Contributors:
 * 	   IBM Corporation - initial API and implementation for JDT/DLTK
 *     Sean W. Quinn - initial adoption for use with PHP from various sources.
 */
package org.eclipse.php.internal.ui.text;

import java.util.Arrays;

import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;

public class PHPHeuristicScanner extends ScriptHeuristicScanner implements IPHPSymbols {
	private static final int[] BLOCK_BEGINNING_KEYWORDS = { TokenIF, TokenFOR, TokenDEF, TokenCASE, TokenCATCH,
			TokenCLASS, TokenWHILE, TokenDO };

	private static final int[] BLOCK_BEGINNING_SYMBOLS = {
		// TODO: Implement block beginning symbols
	};

	private static final int[] BLOCK_MIDDLES = { TokenELSE, TokenELSIF, TokenWHEN };

	private static final int[] BLOCK_ENDINGS = { TokenEND, TokenRBRACE, TokenRBRACKET };

	static {
		Arrays.sort(BLOCK_BEGINNING_KEYWORDS);
		Arrays.sort(BLOCK_BEGINNING_SYMBOLS);
		Arrays.sort(BLOCK_MIDDLES);
		Arrays.sort(BLOCK_ENDINGS);
	}

	/**
	 * Calls
	 * <code>super(document, IPHPPartitions.RUBY_PARTITIONING, IDocument.DEFAULT_CONTENT_TYPE)</code>
	 * .
	 * 
	 * @param document the document to scan.
	 */
	public PHPHeuristicScanner(IDocument document) {
		super(document, IPHPPartitions.PHP_PARTITIONING, IDocument.DEFAULT_CONTENT_TYPE);
	}

	protected PHPHeuristicScanner(final IDocument document, final String partitioning, final String partition) {
		super(document, partitioning, partition);
	}

	public int findBlockBeginningOffset(int offset) {
		try {
			IDocument d = getDocument();
			int line = d.getLineOfOffset(offset);
			int endingCount = 0;
			while (line >= 0) {
				IRegion info = d.getLineInformation(line);
				int start = info.getOffset();
				int end = Math.min(info.getOffset() + info.getLength(), offset);
				setPosition(start);
				while (getPosition() < end) {
					if (isBlockEnding(getPosition(), end)) {
						endingCount++;
					}
				}

				start = info.getOffset();
				end = Math.min(info.getOffset() + info.getLength(), offset);
				setPosition(end);
				while (getPosition() > start) {
					if (isBlockBeginning(start, getPosition())) {
						if (endingCount > 0) {
							endingCount--;
						}
						else {
							return getPosition();
						}
					}
				}

				line--;
			}
		}
		catch (BadLocationException e) {
			DLTKUIPlugin.log(e);
		}
		return NOT_FOUND;
	}

	public int findBlockEndingOffset(int offset) {
		try {
			IDocument d = getDocument();
			int line = d.getLineOfOffset(offset);
			int lineNum = d.getNumberOfLines();
			int beginningCount = 0;
			while (line < lineNum) {
				IRegion info = d.getLineInformation(line);
				int start = Math.max(info.getOffset(), offset);
				int end = info.getOffset() + info.getLength();
				setPosition(end);
				while (getPosition() > start) {
					if (isBlockBeginning(start, getPosition())) {
						beginningCount++;
					}
				}

				start = Math.max(info.getOffset(), offset);
				end = info.getOffset() + info.getLength();
				setPosition(start);
				while (getPosition() < end) {
					if (isBlockEnding(getPosition(), end)) {
						if (beginningCount > 0) {
							beginningCount--;
						}
						else {
							return getPosition();
						}
					}
				}

				line++;
			}
		}
		catch (BadLocationException e) {
			DLTKUIPlugin.log(e);
		}
		return NOT_FOUND;
	}

	@Override
	public int getToken(int position, String s) {
		// TODO Auto-generated method stub
		return 0;
	}

	public boolean isBlockBeginning(int offset, int bound) {
		int token = previousToken(bound, offset);
		while (token != NOT_FOUND) {
			if (Arrays.binarySearch(BLOCK_BEGINNING_SYMBOLS, token) >= 0)
				return true;

			if (Arrays.binarySearch(BLOCK_BEGINNING_KEYWORDS, token) >= 0) {
				int pos = getPosition();
				int prevToken = token;
				token = previousToken(getPosition(), offset);
				if (token == NOT_FOUND || token == TokenEQUAL || prevToken == TokenDO) {
					setPosition(pos + 1);
					return true;
				}
			}

			token = previousToken(getPosition(), offset);
		}

		return false;
	}

	public boolean isBlockMiddle(int offset, int bound) {
		if (Arrays.binarySearch(BLOCK_MIDDLES, nextToken(offset, bound)) >= 0) {
			// setting the position to start of the block keyword
			findNonIdentifierBackward(offset, UNBOUND);
			setPosition(getPosition() + 1);
			return true;
		}
		else {
			return false;
		}
	}

	public boolean isBlockEnding(int offset, int bound) {
		int token = nextToken(offset, bound);
		while (token != NOT_FOUND) {
			if (Arrays.binarySearch(BLOCK_ENDINGS, token) >= 0)
				return true;
			token = nextToken(getPosition(), bound);
		}

		return false;
	}

	public int previousTokenAfterInput(int offset, String appended) {
		try {
			if (getPartition(offset).getType() != IDocument.DEFAULT_CONTENT_TYPE)
				return NOT_FOUND;

			if (appended.length() == 1) {
				int token = getGenericToken(appended.charAt(0));
				if (token != TokenOTHER)
					return token;
			}

			IRegion line = getDocument().getLineInformationOfOffset(offset);
			String content = getDocument().get(line.getOffset(), offset - line.getOffset()) + appended;
			IDocument newDoc = new Document(content);
			PHPHeuristicScanner scanner = new PHPHeuristicScanner(newDoc);
			return scanner.previousToken(content.length(), UNBOUND);
		}
		catch (BadLocationException e) {
			DLTKUIPlugin.log(e);
		}
		return NOT_FOUND;
	}
}
